package org.yunai.swjg.server.module.user.operation;

import org.slf4j.Logger;
import org.yunai.swjg.server.core.service.Online;
import org.yunai.swjg.server.core.service.OnlineContextService;
import org.yunai.swjg.server.core.service.OnlineState;
import org.yunai.swjg.server.core.session.GameSession;
import org.yunai.swjg.server.entity.User;
import org.yunai.swjg.server.module.player.PlayerExitReason;
import org.yunai.swjg.server.module.player.PlayerService;
import org.yunai.swjg.server.module.user.UserMapper;
import org.yunai.swjg.server.rpc.message.S_C.S_C_LoginResultResp;
import org.yunai.swjg.server.rpc.message.S_C.S_C_OnlineDiggedReq;
import org.yunai.yfserver.async.IIoOperation;
import org.yunai.yfserver.common.LoggerFactory;
import org.yunai.yfserver.spring.BeanManager;

/**
 * 帐号登录操作
 * User: yunai
 * Date: 13-3-29
 * Time: 上午12:37
 */
public class UserLoginOperation implements IIoOperation {

    private Logger LOGGER = LoggerFactory.getLogger(LoggerFactory.Logger.login, UserLoginOperation.class);

    private static UserMapper userMapper;
    private static PlayerService playerService;

    private static OnlineContextService onlineContextService;

    static {
        UserLoginOperation.userMapper = BeanManager.getBean(UserMapper.class);
        UserLoginOperation.playerService = BeanManager.getBean(PlayerService.class);

        UserLoginOperation.onlineContextService = BeanManager.getBean(OnlineContextService.class);
    }

    private final Short serverId;
    private final String userName;
    private final String password;
    private volatile GameSession session;

    private volatile User user;
    /**
     * 登录结果：<br />
     * 1 - 登录成功<br />
     * 2 - 帐号不存在<br />
     * 3 - 帐号获密码不正确
     */
    private volatile byte loginResult;

    public UserLoginOperation(GameSession session, Short serverId, String userName, String password) {
        this.serverId = serverId;
        this.userName = userName;
        this.password = password;
        this.session = session;
    }

    @Override
    public State doStart() {
        return State.STARTED;
    }

    @Override
    public State doIo() {
        if (session.isConnected()) {
            user = userMapper.selectUserByUserName(userName);
            if (user == null) {
                loginResult = 2;
            } else if (!user.getPassword().equals(password)) {
                loginResult = 3;
            } else {
                loginResult = 1;
            }
        }
        return State.IO_DONE;
    }

    @Override
    public State doFinish() {
        if (session.isConnected()) {
            if (loginResult == 2 || loginResult == 3) {
                session.write(new S_C_LoginResultResp(loginResult));
            } else if (loginResult == 1) {
                Online online = session.getOnline();
                // 当且仅当用户处于[connected]才继续登录成功逻辑
                // 防止突然收到2个登录请求，导致这里调用的时候，该用户已经处于其他状态
                if (online.getState() == OnlineState.connected) {
                    online.setUser(user);
                    online.setServerId(serverId);

                    // 踢掉之前登录这个服务这个帐号的玩家
                    Online curOnline = onlineContextService.getUser(user.getId());
                    if (curOnline != null && curOnline.getState() != OnlineState.logouting) {
                        online.setState(OnlineState.temp_authed);
                        onlineContextService.addWillAuthUser(online); // TODO 若有N个登录帐号，即willAuthMap里已经有这个用户了，需要在处理下。
                                                                      // TODO 解决方法：如果有，则提示用户稍后重试，即这样也算登录失败

                        LOGGER.info("[doFinish] [用户:{} 由于多点登录被顶下线].", curOnline.getUser().getId());

                        // 发送被顶下线消息
                        curOnline.write(new S_C_OnlineDiggedReq());
                        // 设置退出原因并退出
                        curOnline.setExitReason(PlayerExitReason.MULTI_LOGIN);
                        curOnline.disconnect();
                        return State.FINISHED;
                    }

                    playerService.onPlayerLoad(online);
                } else {
                    LOGGER.error("[doFinish] [login success with error state:{}]", online.getState());
                }
            }
        }
        return State.FINISHED;
    }
}
